#include "StdAfx.h"
#include "Esl_W.h"
#include "ExtData.h"
#include "AdoPtr.h"
//#include "ExtFunc.h"


#define _CRT_SECURE_NO_WARNINGS


CEsl_W::~CEsl_W()
{
	for_each( g_ExtData.begin(), g_ExtData.end(), PairDeleter< int, CExtData*>() );
	g_ExtData.clear();

	for_each( g_CallInfo.begin(), g_CallInfo.end(), PairDeleter< char* ,CCallInfo*>() );
	g_CallInfo.clear();

	if( m_ado )
	{
		delete m_ado;
	}

}
int CEsl_W::init()
{
	if(!m_bInit)
		return -1;

	//if(esl_thread_create_detached(msg_thread_run, &m_esl_h) != ESL_SUCCESS ){
	//	//esl_log("Error starting thread!\n");
	//	esl_disconnect( &m_esl_h );
	//	return -1;
	//}
	if(esl_thread_create_detached(msg_thread_run, this) != ESL_SUCCESS ){
		//esl_log("Error starting thread!\n");
		esl_disconnect( &m_esl_h );
		return -1;
	}
	if( esl_send_recv(&m_esl_h, "event plain CHANNEL_CREATE CHANNEL_ANSWER CHANNEL_DESTROY CUSTOM conference::maintenance sofia::register sofia::unregister") )
	{
		return -1;
	}

	m_ado = new CAdoPtr;
	
	_bstr_t str="Provider=SQLOLEDB.1; Server=CHRIS-PC\\SQLEXPRESS; Database=fs_test; uid=sa; pwd=amt123;";
	m_ado->InitAdoConnection(str, "","" ); 


	return ESL_SUCCESS;
}


esl_status_t CEsl_W::action(const char* str,...)
{
	//if str == "call"
	esl_status_t t;

	if(!strcasecmp(str, "Hangup"))
	{
		return t;
	}

	if(!strcasecmp(str, "Hold"))
	{
		return t;
	}

	if(!strcasecmp(str, "Transfer"))
	{
		return t;
	}


}

void CEsl_W::QueryExtChannel()
{
	char str[1024];
	memset(str, 0, 1024 );
	std::string cmd("show calls");
	_snprintf_s(str, sizeof(str), "api %s count\nconsole_execute: true\n\n", cmd.c_str() );

	if( esl_send_recv( &m_esl_h, str ) )
	{
		return ;
	}

	int cur_count=0;

	if(m_esl_h.last_sr_event)
	{
		if(m_esl_h.last_sr_event->body)
		{	
			char* res = new char[strlen(m_esl_h.last_sr_event->body)+1];
			memset(res, 0, strlen(m_esl_h.last_sr_event->body)+1);
			strncpy(res,m_esl_h.last_sr_event->body,strlen(m_esl_h.last_sr_event->body));
			char* det= strstr(res, " ");
			if(res[1] == '0' )
			{
				delete[] res;
				return ;
			}
			std::string strs(res,1,det-res);
			cur_count = atoi(strs.c_str());
			delete[] res;
		}
	}
	memset( str, 0, 1024 );
	_snprintf_s(str, sizeof(str), "api %s\nconsole_execute: true\n\n", cmd.c_str() );
	if(esl_send_recv( &m_esl_h, str))
	{
		return;
	}
	if(m_esl_h.last_sr_event)
	{
		if( m_esl_h.last_sr_event->body )
		{
			char* res = new char[strlen(m_esl_h.last_sr_event->body)+1];
			memset(res, 0, strlen(m_esl_h.last_sr_event->body)+1);
			strncpy_s(res,strlen(m_esl_h.last_sr_event->body)+1,m_esl_h.last_sr_event->body,strlen(m_esl_h.last_sr_event->body));
			char* det = strstr( res, "call_created_epoch");
			det += strlen("call_created_epoch");
			//std::map<char* , std::string> pPairs;
			for(int i=0;i<cur_count;++i)
			{
				//get caller ID
				char* det_a = strNthstr( det, ",", 7 );
				char* det_b = strchr( det_a, ',' );
				int ileng = det_b - det_a;
				char* pId = new char[ileng+1];
				memset( pId, 0, ileng+1);
				strncpy_s( pId,ileng+1, det_a, ileng );
				//int caller = atoi( pId );
				

				det_b += 1;

				//get callee ID
				det_a = strchr( det_b, ',' ); //skip ip_addr
				det_a += 1;
				det_b = strchr( det_a, ',' );
				ileng = det_b - det_a;
				char* callee = new char[ileng+1];
				memset( callee, 0, ileng+1 );
				strncpy_s( callee, ileng+1, det_a, ileng);
				

				//get aleg
				det_a = strchr( det, ',' );
				ileng = det_a-det;
				char* aleg = new char[ileng+1];
				memset( aleg, 0, ileng+1);
				strncpy_s( aleg, ileng+1, det, ileng );
				//delete[] aleg;
				det_a += 1;

				//get created time
				det_b = strchr( det_a, ',' );
				det_b += 1;
				//skip direction
				det_a = strchr( det_b, ',' );
				ileng = det_a - det_b;
				char* created_time = new char[ileng+1];
				memset( created_time, 0, ileng+1);
				strncpy_s( created_time, ileng+1,  det_b, ileng );

				det_a += 1;
				det_b = strNthstr( det_a, ",", 17 );
				det_a = strchr( det_b, ',' );
				ileng = det_a-det_b;
				char* bleg = new char[ileng+1];
				memset( bleg, 0, ileng+1);
				strncpy_s( bleg, ileng+1, det_b, ileng );

				CCallInfo* pInfo = new CCallInfo;
				strncpy_s( pInfo->CL_caller, pId, strlen(pId) );
				strncpy_s( pInfo->CL_callee, callee, strlen(callee) );
				strncpy_s( pInfo->uuid_a_leg, aleg, strlen(aleg) );
				strncpy_s( pInfo->uuid_b_leg, bleg, strlen(bleg) );
				strncpy_s( pInfo->CL_create_time,created_time, strlen(created_time) );

				
				if( g_ExtData.find( atoi(callee) )!=g_ExtData.end() && g_ExtData.find( atoi(pId) )!=g_ExtData.end() )
				{
					//both caller and callee are extensions
					//we insert two values
					g_CallInfo.insert( std::make_pair( pInfo->CL_caller, pInfo ) );
					g_CallInfo.insert( std::make_pair( pInfo->CL_callee, pInfo ) );
					std::map<int, CExtData*>::iterator iter = g_ExtData.find( atoi(callee) );
					((*iter).second)->u_state = BUSY;
					iter = g_ExtData.find( atoi( pId) );
					((*iter).second)->u_state = BUSY;
					//(((*iter).second)).u_state = BUSY;
					/*((g_ExtData.find( atoi(callee) )).second)->u_state = BUSY;
					((g_ExtData.find( atoi(pId) )).second)->u_state = BUSY;*/
				}else if( g_ExtData.find( atoi(pId) )!=g_ExtData.end() )
				{
					g_CallInfo.insert( std::make_pair( pInfo->CL_caller, pInfo ) );
					std::map<int, CExtData*>::iterator iter = g_ExtData.find( atoi(pId) );
					((*iter).second)->u_state = BUSY;
					//((g_ExtData.find( atoi(pId) )).second)->u_state = BUSY;
				}else
				{
					g_CallInfo.insert( std::make_pair( pInfo->CL_callee, pInfo ) );
					std::map<int, CExtData*>::iterator iter = g_ExtData.find( atoi(callee) );
					((*iter).second)->u_state = BUSY;
					//((g_ExtData.find( atoi(callee) )).second)->u_state = BUSY;
				}
				
				delete[] bleg;
				delete[] created_time;
				delete[] aleg;		
				delete[] callee;
				delete[] pId;
			}

			delete[] res;
			

		}
	}

}

void CEsl_W::UIstatusFired(char* caller, char* callee, int& p_caller, int& p_callee,BOOL bt /* = TRUE */ )
{
	//bt == TURE
	//for channels create
	if( !strncasecmp(caller,"5934",4 ))
		caller += 4;
	if( !strncasecmp(callee, "5934", 4) )
		callee += 4;
	if( g_ExtData.find( atoi(callee) )!=g_ExtData.end() && g_ExtData.find( atoi(caller) )!=g_ExtData.end() )
	{
		//both caller and callee are extensions
		//we insert two values
		std::map<int, CExtData*>::iterator iter = g_ExtData.find( atoi(callee) );
		((*iter).second)->u_state = bt? BUSY : IDLE;
		iter = g_ExtData.find( atoi( caller) );
		((*iter).second)->u_state = bt? BUSY : IDLE;
		p_callee = atoi(callee );
		p_caller = atoi( caller );
		//(((*iter).second)).u_state = BUSY;
		/*((g_ExtData.find( atoi(callee) )).second)->u_state = BUSY;
		((g_ExtData.find( atoi(pId) )).second)->u_state = BUSY;*/
	}else if( g_ExtData.find( atoi(caller) )!=g_ExtData.end() )
	{
		std::map<int, CExtData*>::iterator iter = g_ExtData.find( atoi(caller) );
		((*iter).second)->u_state = bt? BUSY : IDLE;
		p_callee = 0;
		p_caller = atoi( caller );
		//((g_ExtData.find( atoi(pId) )).second)->u_state = BUSY;
	}else if(g_ExtData.find( atoi(callee) )!=g_ExtData.end() )
	{
		std::map<int, CExtData*>::iterator iter = g_ExtData.find( atoi(callee) );
		((*iter).second)->u_state = bt? BUSY : IDLE;
		p_caller = 0;
		p_callee = atoi(callee);
	}

}

void CEsl_W::QueryRegUser()
{
	char str[1024];
	memset(str, 0, 1024 );
	std::string cmd("show registrations");

	_snprintf_s(str, sizeof(str), "api %s count\nconsole_execute: true\n\n", cmd.c_str() );

	if(esl_send_recv( &m_esl_h, str ) )
	{
		return ;
	}

	int cur_count=0;

	if(m_esl_h.last_sr_event)
	{
		if(m_esl_h.last_sr_event->body )
		{
			char* res = new char[strlen(m_esl_h.last_sr_event->body)+1];
			memset(res, 0, strlen(m_esl_h.last_sr_event->body)+1);
			strncpy(res,m_esl_h.last_sr_event->body,strlen(m_esl_h.last_sr_event->body));
			char* det= strstr(res, " ");
			if(res[1] == '0' )
			{
				delete[] res;
				return ;
			}

			/*if(!strcasecmp(res, "0 total."))
				return ;*/
			std::string strs(res,1,det-res);

			/*char* dest = new char[det - res];
			memset(dest, 0, det - res );
			strncpy_s( dest, det-res, res, det-res );*/
			cur_count = atoi(strs.c_str());
			//delete[] dest;
			delete[] res;
		}
	}
	
	memset(str,0,1024);
	_snprintf_s(str, sizeof(str), "api %s\nconsole_execute: true\n\n", cmd.c_str() );
	if(esl_send_recv( &m_esl_h, str))
	{
		return;
	}
	if(m_esl_h.last_sr_event)
	{
		if(m_esl_h.last_sr_event->body)
		{
			char* res = new char[strlen(m_esl_h.last_sr_event->body)+1];
			memset(res, 0, strlen(m_esl_h.last_sr_event->body)+1);
			strncpy(res,m_esl_h.last_sr_event->body,strlen(m_esl_h.last_sr_event->body));
			char* det = strstr( res, "hostname");
			det +=8;
			if(!strncasecmp(det, ",",1))
			{
				//has metadata
				det = strstr( det, "metadata");
				det += 9;
			}
			//eg the body format
			//reg_user,realm,token,url,expires,network_ip,network_port,network_proto,hostname(,metadata)
			//9019,172.16.1.100,300137699@172.16.3.114,sofia/internal/sip:9019@172.16.3.114:5062,1347443883,172.16.3.114,5062,udp,server1.bjliveneo.com
			
			//now det point to '9'
			
			

			
			for( int i=0; i<cur_count; ++i)
			{
				CExtData* pData = new CExtData;
				pData->u_breg = true;
				strncpy_s( pData->u_id, det, 5);
				int uid = atoi(pData->u_id);
				
				det += 6;

				//skip the realm token
				det = strNthstr(det, ",",2);
				char* dest = strstr(det, ",");
				strncpy_s(pData->u_url, det, dest-det);
				det = ++dest;
				/*str += "";
				str += ",";*/
				//skip expires
				det = strstr(det, ",");
				det += 1;
				dest = strstr(det, ",");
				strncpy_s(pData->u_regIP, det, dest-det);
				det = ++dest;
				//port
				char port[255]={0};
				dest = strstr(det, ",");
				strncpy_s( port, det, dest-det);
				pData->u_port = atoi(port);
				det = ++dest;

				//state
				dest = strstr(det, ",");
				strncpy_s(pData->u_regStatus,det,dest-det);
				det = ++dest;

				
				//next record
				det = strstr(det, "\n");
				det +=1;


				g_ExtData.insert(std::make_pair(uid, pData));
				CString logstr("Extension ");
				logstr += pData->u_id;
				logstr += " registered from ";
				logstr += pData->u_regIP;
				logstr += ".";
				LPTSTR lpsz = (LPTSTR)(LPCTSTR)logstr;
				::PostMessage( m_pParentWnd, WM_LOG_STATUS, NULL, (LPARAM)lpsz );

				CString prestr;
				prestr.Format( _T("if not exists(SELECT * FROM dbo.[FS_USER] WHERE US_EXT = %d)\n"), uid );
				CString str;
				str.Format(_T("'%d','") , uid );
				str += pData->u_url;
				str += "','";
				str += pData->u_regIP;
				str += "','";
				str += pData->u_regStatus;
				str += "','";
				str += "')";
				CString strtmp("INSERT INTO dbo.[FS_USER]\nVALUES (");
				strtmp += str;
				prestr += strtmp;
				_bstr_t st = (_bstr_t)prestr;
				m_ado->Execute(st);

				::SendMessage(m_pParentWnd, WM_STATUS_MD, (WPARAM)MAKELONG(uid, USER_REGED), NULL );
			}
			delete[] res;
		}
	}
}

void CEsl_W::HandleEvent(esl_event_t* event/* =NULL */)
{

	if(!event)
		return;
	const char* str = esl_event_get_header( event, "Event-Subclass");
	if(str)
	{
		//Event-Subclass
		//reg, unreg
		char* uid = esl_event_get_header( event, "username");
		int id = atoi(uid);
		if(!strcasecmp( str, "sofia::register"))
		{
			if( g_ExtData.find(id) != g_ExtData.end() )
			{
				return ;
			}
			CExtData* pData = new CExtData;
			pData->u_breg = true;
			strncpy_s( pData->u_id, uid, strlen(uid) );
			pData->u_port = atoi( esl_event_get_header(event, "network-port") );
			strncpy_s( pData->u_regIP, esl_event_get_header(event, "network-ip"), strlen(esl_event_get_header(event, "network-ip")) );
			strncpy_s( pData->u_regStatus, esl_event_get_header(event, "status"), strlen( esl_event_get_header(event, "status")) );
			strncpy_s( pData->u_url, esl_event_get_header(event, "contact"), strlen( esl_event_get_header(event, "contact")) );
			strncpy_s( pData->u_agent, esl_event_get_header(event, "user-agent"), strlen(esl_event_get_header(event, "user-agent")) );
			g_ExtData.insert( std::make_pair( id, pData) );

			CString logstr("Extension ");
			logstr += pData->u_id;
			logstr += " registered from ";
			logstr += pData->u_regIP;
			logstr += ".";
			LPTSTR lpsz = (LPTSTR)(LPCTSTR)logstr;
			::PostMessage( m_pParentWnd, WM_LOG_STATUS, NULL ,(LPARAM)lpsz);


			CString prestr;
			prestr.Format( _T("if not exists(SELECT * FROM dbo.[FS_USER] WHERE US_EXT = %d)\n"), id );
			CString str;
			str.Format(_T("'%d','") , id );
			str += pData->u_url;
			str += "','";
			str += pData->u_regIP;
			str += "','";
			str += pData->u_regStatus;
			str += "','";
			str += pData->u_agent;
	
			str += "')";
			CString strtmp("INSERT INTO dbo.[FS_USER]\nVALUES (");
			strtmp += str;
			prestr += strtmp;
			_bstr_t st = (_bstr_t)prestr;
			m_ado->Execute(st);

			::PostMessage( m_pParentWnd, WM_STATUS_MD, (WPARAM)MAKELONG(id,USER_REG), (LPARAM)uid );
		}
		else{
			
			CString strlog;
			strlog.Format( _T("Extension %d unregistered."), id );
			LPTSTR lpsz = (LPTSTR)(LPCTSTR)strlog;
			::PostMessage( m_pParentWnd, WM_LOG_STATUS,  NULL,(LPARAM)lpsz );

			CString str;
			str.Format( _T("DELETE FROM dbo.[FS_USER] WHERE US_EXT = %d "), id );
			_bstr_t strsql = (_bstr_t)str;
			m_ado->Execute( strsql );
			g_ExtData.erase( id );
			::PostMessage( m_pParentWnd, WM_STATUS_MD, (WPARAM)MAKELONG(id,USER_UNREG), (LPARAM)uid );
		}

	}
	else{
		
		//handle other event
		const char* strtmp = esl_event_get_header( event, "Event-Name");
		if( strtmp )
		{
			if( !strcasecmp( strtmp, "CHANNEL_CREATE") || !strcasecmp(strtmp, "CHANNEL_ANSWER") )
			{
				//a-leg b-leg
				int pcaller, pcallee;
				char* created = esl_event_get_header(event,"Event-Date-Local");
				char* i_uuid = esl_event_get_header( event, "Unique-ID" );
				char* caller_num = esl_event_get_header( event, "Caller-Caller-ID-Number" );
				char* caller_direction = esl_event_get_header( event, "Caller-Direction" );
				char* dest = esl_event_get_header(event, "Caller-Destination-Number");
				UIstatusFired( caller_num, dest,pcaller, pcallee );

				if( !strncasecmp(caller_num,"5934",4 ))
					caller_num += 4;
				if( !strncasecmp(dest, "5934", 4) )
					dest += 4;


				if( dest[0]=='0' && dest[1]=='0')
					dest += 2;
				else if( dest[0] == '0'){
					dest += 1;
				}
				char* callstate = esl_event_get_header( event, "Answer-State");
				char* call_uuid = esl_event_get_header( event, "Channel-Call-UUID");
				CString str("INSERT INTO dbo.[channels]\nVALUES (");
				CString sql;
				sql += "'";
				sql += i_uuid;

				CString prestr("IF exists( select * from dbo.[channels] where uuid = ");
				prestr += sql;
				prestr += "')\n UPDATE dbo.[channels] set created = '";
				prestr += created;
				prestr += "', callstate = '";
				prestr += callstate;
				prestr += "' where uuid = ";
				prestr += sql;
				prestr += "'\nelse ";

				sql += "','";
				sql += caller_direction;
				sql += "','";
				sql += created;
				sql += "','";
				sql += caller_num;
				sql += "','";
				sql += dest;
				sql +="','";
				sql += callstate;
				sql += "','";
				sql += call_uuid;
				sql +="')";
				//sql.Format( _T("'%s','%s','%s','%d','%d','%s','%s')" ), i_uuid, caller_direction, created, atoi(caller_num), atoi(dest),callstate,call_uuid);
				str += sql;
				prestr += str;
				_bstr_t sqlstr = (_bstr_t)prestr;
				bool bret = m_ado->Execute( sqlstr );

				CString strlogs;
				strlogs += caller_num;
				strlogs += " calling ";
				strlogs += dest;
				strlogs += ".... callstate:= ";
				strlogs += callstate;
				LPTSTR lpsz = (LPTSTR)(LPCTSTR)strlogs;
				::SendMessage( m_pParentWnd, WM_LOG_STATUS, (WPARAM)MAKELONG(pcaller,pcallee), (LPARAM)lpsz );
			}

			if( !strcasecmp ( strtmp, "CHANNEL_DESTROY") )
			{
				//delete channels from table
				int pcaller,pcallee;
				char* i_uuid = esl_event_get_header( event, "Unique-ID" );
				CString tmp("DELETE FROM dbo.[channels] WHERE uuid =");
				tmp += "'";
				tmp += i_uuid;
				tmp += "'";
				_bstr_t strsql = (_bstr_t)tmp;
				m_ado->Execute( strsql );

				//insert into call_record
				//may get null

				/*char* caller = esl_event_get_header( event, "Caller-Caller-ID-Number" );*/
				char* caller = esl_event_get_header( event, "Other-Leg-ANI" );
				if( !caller ){
					caller = esl_event_get_header( event, "Caller-Caller-ID-Number" );
				}
				char* callee = esl_event_get_header( event, "Other-Leg-Destination-Number" );
				if( !callee ){
					callee = esl_event_get_header( event, "Caller-Destination-Number" );
				}
				/*char* callee = esl_event_get_header( event, "Caller-Destination-Number" );*/
				
			
				//change UI status
				ASSERT(caller != NULL );
				ASSERT( callee != NULL );
				UIstatusFired( caller, callee, pcaller, pcallee, FALSE );

				if( !strncasecmp(caller,"5934",4 ))
					caller += 4;
				if( !strncasecmp(callee, "5934", 4) )
					callee += 4;

				if( callee )
				{
					if( callee[0]=='0' && callee[1]=='0')
						callee += 2;
					else if( callee[0] == '0'){
						callee += 1;
					}
				}

				char* end_time = esl_event_get_header( event, "Event-Date-Local");	
				char* start_time = esl_event_get_header( event, "variable_start_stamp" );
				char* answer_time = esl_event_get_header(event, "variable_answer_stamp" );
				char* s_time = esl_event_get_header( event, "variable_start_epoch" );
				char* e_time = esl_event_get_header( event, "variable_end_epoch");
				CString temp("INSERT INTO dbo.[FS_CALLRECORD]\n VALUES (");
				CString scond("IF not exists (select * from dbo.[FS_CALLRECORD] where caller = '");
				scond += caller;
				scond += "' and  callee = '";
				temp += "'";
				temp += caller;
				temp += "' , '";
				scond += callee;
				scond += "' and  start_time = '";
				temp += callee;
				temp += "','";
				scond += start_time;
				scond += "' and  answerd_time = '";
				temp += start_time;
				temp += "','";
				scond += answer_time;
				scond += "' and  e_time = '";
				temp += answer_time;
				temp += "','";
				scond += end_time;
				scond += "' and  dur_time = ";
				temp += end_time;
				temp += "',";
				
				int durtime = atoi(e_time) - atoi(s_time );
				int hour = durtime/3600;
				int mins = durtime/60;
				int cecs = durtime%60;

				CString durgtime;
				durgtime.Format( _T("'%d mins %d secs'"), mins, cecs );
				scond += durgtime;
				scond += ")\n";
				temp += durgtime;
				temp +=")";
				scond += temp;

				_bstr_t sqlt = (_bstr_t)scond;
				bool bret = m_ado->Execute( sqlt );


				CString strlogs;
				strlogs += caller;
				strlogs += " calling ";
				strlogs += callee;
				strlogs += "... ended!. duration_time:= ";
				strlogs += durgtime;
				LPTSTR lpsz = (LPTSTR)(LPCTSTR)strlogs;
				::SendMessage( m_pParentWnd, WM_LOG_STATUS, (WPARAM)MAKELONG(pcaller,pcallee), (LPARAM)lpsz );

			}
		}
	}
	

	return;



}

int GetUserCount()
{
	return g_ExtData.size();
}